package com.hjy.im.protocol;

import com.hjy.im.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * 编码器与解码器方法源于父类ByteToMessageCodec，通过该类可以自定义编码器与解码器，
 * 泛型类型为被编码与被解码的类。此处使用了自定义类Message，代表消息
 *
 * 编码器负责将附加信息与正文信息写入到ByteBuf中，其中附加信息总字节数最好为2n，
 * 不足需要补齐。正文内容如果为对象，需要通过序列化将其放入到ByteBuf中
 * 解码器负责将ByteBuf中的信息取出，并放入List中，该List用于将信息传递给下一个handler
 */
public class MessageCodec extends ByteToMessageCodec<Message> {


    @Override
    public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        //设置魔数 4 个字节
        out.writeBytes(new byte[]{'N', 'Y' ,'I', 'M'});
        //设置版本号 1个字节
        out.writeByte(1);
        //设置序列化的方式1 个字节
        out.writeByte(1);
        //设置指令类型1个字节
        out.writeByte(msg.getMessageType());
        //设置请求序号 4  个字节
        out.writeInt(msg.getSequenceId());
        //为补齐16个字节，填充1个字节的数据
        out.writeByte(0xff);

        //后去序列化后的msg
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] bytes = bos.toByteArray();
        //获取并设置正文长度，长度用4个字节表示
        out.writeInt(bytes.length);
        //设置消息正文
        out.writeBytes(bytes);


    }

    @Override
    public
    void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //获取魔数
        int magic = in.readInt();
        //获取版本号
        byte version = in.readByte();
        //获取序列化方式
        byte seqType = in.readByte();
        //获取指令类型
        byte messageType = in.readByte();
        //获取请求序号
        int sequenceId = in.readInt();
        //移除补齐字段
        in.readByte();
        //获取正文长度
        int length = in.readInt();
        //后去正文
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0 , length);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
        Message msg = (Message) ois.readObject();
        //将信息放入list中 ，传递给下一个 handler
        out.add(msg);

        // 打印获得的信息正文
        System.out.println("===========魔数===========");
        System.out.println(magic);
        System.out.println("===========版本号===========");
        System.out.println(version);
        System.out.println("===========序列化方法===========");
        System.out.println(seqType);
        System.out.println("===========指令类型===========");
        System.out.println(messageType);
        System.out.println("===========请求序号===========");
        System.out.println(sequenceId);
        System.out.println("===========正文长度===========");
        System.out.println(length);
        System.out.println("===========正文===========");
        System.out.println(msg);
    }
}
